/*
 * Copyright (C) 2014 Akexorcist
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wzb.sppnew;

import java.util.ArrayList;
import java.util.Set;

import com.wzb.hhunew.util.Common;
import com.wzb.hhunew.util.LogUtil;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

@SuppressLint("NewApi")
public class BluetoothSPP {
	// Listener for Bluetooth Status & Connection
	private BluetoothStateListener mBluetoothStateListener = null;
	private OnDataReceivedListener mDataReceivedListener = null;
	private BluetoothConnectionListener mBluetoothConnectionListener = null;
	private AutoConnectionListener mAutoConnectionListener = null;

	// Context from activity which call this class
	private Context mContext;

	// Local Bluetooth adapter
	private BluetoothAdapter mBluetoothAdapter = null;

	// Member object for the chat services
	private BluetoothService mChatService = null;

	// Name and Address of the connected device
	private String mDeviceName = null;
	private String mDeviceAddress = null;

	private boolean isAutoConnecting = false;
	private boolean isAutoConnectionEnabled = false;
	private boolean isConnected = false;
	private boolean isConnecting = false;
	private boolean isServiceRunning = false;

	private String keyword = "";
	private boolean isAndroid = BluetoothState.DEVICE_ANDROID;

	private BluetoothConnectionListener bcl;
	private int c = 0;

	public BluetoothSPP(Context context) {
		mContext = context;
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	}

	public interface BluetoothStateListener {
		public void onServiceStateChanged(int state);
	}

	public interface OnDataReceivedListener {
		public void onDataReceived(byte[] data, String message);
	}

	public interface BluetoothConnectionListener {
		public void onDeviceConnected(String name, String address);

		public void onDeviceDisconnected();

		public void onDeviceConnectionFailed();
	}

	public interface AutoConnectionListener {
		public void onAutoConnectionStarted();

		public void onNewConnection(String name, String address);
	}

	public boolean isBluetoothAvailable() {
		try {
			if (mBluetoothAdapter == null || mBluetoothAdapter.getAddress().equals(null))
				return false;
		} catch (NullPointerException e) {
			return false;
		}
		return true;
	}

	public boolean isConnected() {
		return isConnected;
	}

	public boolean isBluetoothEnabled() {
		return mBluetoothAdapter.isEnabled();
	}

	public boolean isServiceAvailable() {
		return mChatService != null;
	}

	public boolean isAutoConnecting() {
		return isAutoConnecting;
	}

	public boolean startDiscovery() {
		return mBluetoothAdapter.startDiscovery();
	}

	public boolean isDiscovery() {
		return mBluetoothAdapter.isDiscovering();
	}

	public boolean cancelDiscovery() {
		return mBluetoothAdapter.cancelDiscovery();
	}

	public void setupService() {
		mChatService = new BluetoothService(mContext, mHandler);
	}

	public BluetoothAdapter getBluetoothAdapter() {
		return mBluetoothAdapter;
	}

	public int getServiceState() {
		if (mChatService != null)
			return mChatService.getState();
		else
			return -1;
	}

	public void startService(boolean isAndroid) {
		if (mChatService != null) {
			if (mChatService.getState() == BluetoothState.STATE_NONE) {
				isServiceRunning = true;
				mChatService.start(isAndroid);
				BluetoothSPP.this.isAndroid = isAndroid;
			}
		}
	}

	public void stopService() {
		if (mChatService != null) {
			isServiceRunning = false;
			mChatService.stop();
		}
		new Handler().postDelayed(new Runnable() {
			public void run() {
				if (mChatService != null) {
					isServiceRunning = false;
					mChatService.stop();
				}
			}
		}, 500);
	}

	public void setDeviceTarget(boolean isAndroid) {
		stopService();
		startService(isAndroid);
		BluetoothSPP.this.isAndroid = isAndroid;
	}

	@SuppressLint("HandlerLeak")
	private final Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
			LogUtil.logMessage("wzb", "bt state:" + msg.what + " value:" + Common.bytesToHexString((byte[]) msg.obj));
			switch (msg.what) {
			case BluetoothState.MESSAGE_WRITE:
				break;
			case BluetoothState.MESSAGE_READ:
				byte[] readBuf = (byte[]) msg.obj;
				String readMessage = new String(readBuf);
				// LogUtil.logMessage("wzb",
				// "readbuf:"+Common.bytesToHexString(readBuf)+"
				// msg:"+readMessage);
				if (readBuf != null && readBuf.length > 0) {
					if (mDataReceivedListener != null)
						mDataReceivedListener.onDataReceived(readBuf, readMessage);
				}
				break;
			case BluetoothState.MESSAGE_DEVICE_NAME:
				mDeviceName = msg.getData().getString(BluetoothState.DEVICE_NAME);
				mDeviceAddress = msg.getData().getString(BluetoothState.DEVICE_ADDRESS);
				if (mBluetoothConnectionListener != null)
					mBluetoothConnectionListener.onDeviceConnected(mDeviceName, mDeviceAddress);
				isConnected = true;
				break;
			case BluetoothState.MESSAGE_TOAST:
				Toast.makeText(mContext, msg.getData().getString(BluetoothState.TOAST), Toast.LENGTH_SHORT).show();
				break;
			case BluetoothState.MESSAGE_STATE_CHANGE:
				if (mBluetoothStateListener != null)
					mBluetoothStateListener.onServiceStateChanged(msg.arg1);
				if (isConnected && msg.arg1 != BluetoothState.STATE_CONNECTED) {
					if (mBluetoothConnectionListener != null)
						mBluetoothConnectionListener.onDeviceDisconnected();
					if (isAutoConnectionEnabled) {
						isAutoConnectionEnabled = false;
						autoConnect(keyword);
					}
					isConnected = false;
					mDeviceName = null;
					mDeviceAddress = null;
				}

				if (!isConnecting && msg.arg1 == BluetoothState.STATE_CONNECTING) {
					isConnecting = true;
				} else if (isConnecting) {
					if (msg.arg1 != BluetoothState.STATE_CONNECTED) {
						if (mBluetoothConnectionListener != null)
							mBluetoothConnectionListener.onDeviceConnectionFailed();
					}
					isConnecting = false;
				}
				break;
			}
		}
	};

	public void stopAutoConnect() {
		isAutoConnectionEnabled = false;
	}

	public void connect(Intent data) {
		LogUtil.logMessage("wzb", "isserviceok" + isServiceAvailable());
		String address = data.getExtras().getString(BluetoothState.EXTRA_DEVICE_ADDRESS);
		BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
		mChatService.connect(device);
	}

	public void connect(String address) {
		BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
		mChatService.connect(device);
	}

	public void disconnect() {
		if (mChatService != null) {
			isServiceRunning = false;
			mChatService.stop();
			if (mChatService.getState() == BluetoothState.STATE_NONE) {
				isServiceRunning = true;
				mChatService.start(BluetoothSPP.this.isAndroid);
			}
		}
	}

	public void setBluetoothStateListener(BluetoothStateListener listener) {
		mBluetoothStateListener = listener;
	}

	public void setOnDataReceivedListener(OnDataReceivedListener listener) {
		mDataReceivedListener = listener;
	}

	public void setBluetoothConnectionListener(BluetoothConnectionListener listener) {
		mBluetoothConnectionListener = listener;
	}

	public void setAutoConnectionListener(AutoConnectionListener listener) {
		mAutoConnectionListener = listener;
	}

	public void enable() {
		mBluetoothAdapter.enable();
	}

	public void send(byte[] data, boolean CRLF) {
		if (mChatService.getState() == BluetoothState.STATE_CONNECTED) {
			if (CRLF) {
				byte[] data2 = new byte[data.length + 2];
				for (int i = 0; i < data.length; i++)
					data2[i] = data[i];
				data2[data2.length - 2] = 0x0A;
				data2[data2.length - 1] = 0x0D;
				mChatService.write(data2);
			} else {
				mChatService.write(data);
			}
		}
	}

	public void send(String data, boolean CRLF) {
		if (mChatService.getState() == BluetoothState.STATE_CONNECTED) {
			if (CRLF)
				data += "\r\n";
			mChatService.write(data.getBytes());
		}
	}

	public String getConnectedDeviceName() {
		return mDeviceName;
	}

	public String getConnectedDeviceAddress() {
		return mDeviceAddress;
	}

	public String[] getPairedDeviceName() {
		int c = 0;
		Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
		String[] name_list = new String[devices.size()];
		for (BluetoothDevice device : devices) {
			name_list[c] = device.getName();
			c++;
		}
		return name_list;
	}

	public String[] getPairedDeviceAddress() {
		int c = 0;
		Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
		String[] address_list = new String[devices.size()];
		for (BluetoothDevice device : devices) {
			address_list[c] = device.getAddress();
			c++;
		}
		return address_list;
	}

	public void autoConnect(String keywordName) {
		if (!isAutoConnectionEnabled) {
			keyword = keywordName;
			isAutoConnectionEnabled = true;
			isAutoConnecting = true;
			if (mAutoConnectionListener != null)
				mAutoConnectionListener.onAutoConnectionStarted();
			final ArrayList<String> arr_filter_address = new ArrayList<String>();
			final ArrayList<String> arr_filter_name = new ArrayList<String>();
			String[] arr_name = getPairedDeviceName();
			String[] arr_address = getPairedDeviceAddress();
			for (int i = 0; i < arr_name.length; i++) {
				if (arr_name[i].contains(keywordName)) {
					arr_filter_address.add(arr_address[i]);
					arr_filter_name.add(arr_name[i]);
				}
			}

			bcl = new BluetoothConnectionListener() {
				public void onDeviceConnected(String name, String address) {
					bcl = null;
					isAutoConnecting = false;
				}

				public void onDeviceDisconnected() {
				}

				public void onDeviceConnectionFailed() {
					Log.e("wzb", "Failed");
					if (isServiceRunning) {
						if (isAutoConnectionEnabled) {
							c++;
							if (c >= arr_filter_address.size())
								c = 0;
							connect(arr_filter_address.get(c));
							Log.e("CHeck", "Connect");
							if (mAutoConnectionListener != null)
								mAutoConnectionListener.onNewConnection(arr_filter_name.get(c),
										arr_filter_address.get(c));
						} else {
							bcl = null;
							isAutoConnecting = false;
						}
					}
				}
			};

			setBluetoothConnectionListener(bcl);
			c = 0;
			if (mAutoConnectionListener != null)
				mAutoConnectionListener.onNewConnection(arr_name[c], arr_address[c]);
			if (arr_filter_address.size() > 0)
				connect(arr_filter_address.get(c));
			else
				Toast.makeText(mContext, "Device name mismatch", Toast.LENGTH_SHORT).show();
		}
	}
}
